# -*- coding: utf-8 -*-
"""
用户存储配额模型
@api-version: 1.0.0
// REF: API-NETDISK-004
"""

from datetime import datetime
from . import db
from .user import User

class UserStorageQuota(db.Model):
    """用户存储配额模型
    
    用于管理用户的存储空间配额和使用统计
    支持配额限制和使用情况监控
    """
    __tablename__ = 'user_storage_quotas'
    
    id = db.Column(db.Integer, primary_key=True, comment='配额ID')
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), unique=True, nullable=False, comment='用户ID')
    quota_limit = db.Column(db.BigInteger, nullable=False, default=10737418240, comment='配额限制（字节，默认10GB）')
    used_space = db.Column(db.BigInteger, default=0, comment='已使用空间（字节）')
    file_count = db.Column(db.Integer, default=0, comment='文件数量')
    folder_count = db.Column(db.Integer, default=0, comment='文件夹数量')
    last_calculated_at = db.Column(db.DateTime, comment='最后计算时间')
    created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, comment='创建时间')
    updated_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, 
                          onupdate=datetime.utcnow, comment='更新时间')
    
    # 关联关系
    user = db.relationship('User', backref=db.backref('storage_quota', uselist=False))
    
    # 表级约束
    __table_args__ = (
        db.CheckConstraint('quota_limit > 0', name='chk_quotas_quota_limit'),
        db.CheckConstraint('used_space >= 0', name='chk_quotas_used_space'),
        db.CheckConstraint('file_count >= 0', name='chk_quotas_file_count'),
        db.CheckConstraint('folder_count >= 0', name='chk_quotas_folder_count'),
    )
    
    def __init__(self, user_id, quota_limit=10737418240):  # 默认10GB
        self.user_id = user_id
        self.quota_limit = quota_limit
        self.used_space = 0
        self.file_count = 0
        self.folder_count = 0
        self.last_calculated_at = None
    
    def get_usage_percent(self):
        """获取使用百分比"""
        if self.quota_limit <= 0:
            return 0.0
        return min(100.0, (self.used_space / self.quota_limit) * 100)
    
    def get_available_space(self):
        """获取可用空间（字节）"""
        return max(0, self.quota_limit - self.used_space)
    
    def is_quota_exceeded(self):
        """检查是否超出配额"""
        return self.used_space > self.quota_limit
    
    def is_quota_warning(self, warning_threshold=0.8):
        """检查是否达到配额警告阈值"""
        return self.get_usage_percent() >= (warning_threshold * 100)
    
    def can_upload(self, file_size):
        """检查是否可以上传指定大小的文件"""
        return (self.used_space + file_size) <= self.quota_limit
    
    def add_file(self, file_size):
        """添加文件（更新统计）"""
        self.used_space += file_size
        self.file_count += 1
        self.updated_at = datetime.utcnow()
        db.session.commit()
    
    def remove_file(self, file_size):
        """移除文件（更新统计）"""
        self.used_space = max(0, self.used_space - file_size)
        self.file_count = max(0, self.file_count - 1)
        self.updated_at = datetime.utcnow()
        db.session.commit()
    
    def add_folder(self):
        """添加文件夹（更新统计）"""
        self.folder_count += 1
        self.updated_at = datetime.utcnow()
        db.session.commit()
    
    def remove_folder(self):
        """移除文件夹（更新统计）"""
        self.folder_count = max(0, self.folder_count - 1)
        self.updated_at = datetime.utcnow()
        db.session.commit()
    
    def update_quota_limit(self, new_limit):
        """更新配额限制"""
        if new_limit <= 0:
            raise ValueError("配额限制必须大于0")
        
        self.quota_limit = new_limit
        self.updated_at = datetime.utcnow()
        db.session.commit()
    
    def recalculate_usage(self):
        """重新计算使用情况"""
        from .virtual_file import VirtualFile
        
        # 计算实际使用空间和文件数量
        result = db.session.query(
            db.func.coalesce(db.func.sum(
                db.case([(VirtualFile.is_folder == False, VirtualFile.file_size)], else_=0)
            ), 0).label('used_space'),
            db.func.coalesce(db.func.sum(
                db.case([(VirtualFile.is_folder == False, 1)], else_=0)
            ), 0).label('file_count'),
            db.func.coalesce(db.func.sum(
                db.case([(VirtualFile.is_folder == True, 1)], else_=0)
            ), 0).label('folder_count')
        ).filter(VirtualFile.owner_id == self.user_id).first()
        
        self.used_space = result.used_space
        self.file_count = result.file_count
        self.folder_count = result.folder_count
        self.last_calculated_at = datetime.utcnow()
        self.updated_at = datetime.utcnow()
        
        db.session.commit()
        
        return {
            'used_space': self.used_space,
            'file_count': self.file_count,
            'folder_count': self.folder_count
        }
    
    def get_formatted_size(self, size_bytes):
        """获取格式化的大小"""
        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
            if size_bytes < 1024.0:
                return f"{size_bytes:.1f} {unit}"
            size_bytes /= 1024.0
        return f"{size_bytes:.1f} PB"
    
    def get_formatted_used_space(self):
        """获取格式化的已使用空间"""
        return self.get_formatted_size(self.used_space)
    
    def get_formatted_quota_limit(self):
        """获取格式化的配额限制"""
        return self.get_formatted_size(self.quota_limit)
    
    def get_formatted_available_space(self):
        """获取格式化的可用空间"""
        return self.get_formatted_size(self.get_available_space())
    
    @staticmethod
    def get_or_create(user_id, quota_limit=10737418240):
        """获取或创建用户配额记录"""
        quota = UserStorageQuota.query.filter_by(user_id=user_id).first()
        if not quota:
            quota = UserStorageQuota(user_id=user_id, quota_limit=quota_limit)
            db.session.add(quota)
            db.session.commit()
        return quota
    
    @staticmethod
    def get_quota_stats():
        """获取全局配额统计"""
        result = db.session.query(
            db.func.count(UserStorageQuota.id).label('total_users'),
            db.func.coalesce(db.func.sum(UserStorageQuota.used_space), 0).label('total_used'),
            db.func.coalesce(db.func.sum(UserStorageQuota.quota_limit), 0).label('total_quota'),
            db.func.coalesce(db.func.sum(UserStorageQuota.file_count), 0).label('total_files'),
            db.func.coalesce(db.func.sum(UserStorageQuota.folder_count), 0).label('total_folders')
        ).first()
        
        return {
            'total_users': result.total_users,
            'total_used_space': result.total_used,
            'total_quota_limit': result.total_quota,
            'total_file_count': result.total_files,
            'total_folder_count': result.total_folders,
            'average_usage_percent': (result.total_used / result.total_quota * 100) if result.total_quota > 0 else 0
        }
    
    @staticmethod
    def get_users_over_quota():
        """获取超出配额的用户"""
        return UserStorageQuota.query.filter(
            UserStorageQuota.used_space > UserStorageQuota.quota_limit
        ).all()
    
    @staticmethod
    def get_users_near_quota(warning_threshold=0.8):
        """获取接近配额限制的用户"""
        threshold_bytes = UserStorageQuota.quota_limit * warning_threshold
        return UserStorageQuota.query.filter(
            UserStorageQuota.used_space >= threshold_bytes
        ).all()
    
    @staticmethod
    def batch_recalculate_all():
        """批量重新计算所有用户的配额使用情况"""
        quotas = UserStorageQuota.query.all()
        updated_count = 0
        
        for quota in quotas:
            try:
                quota.recalculate_usage()
                updated_count += 1
            except Exception as e:
                # 重新计算配额失败，跳过该用户
                continue
        
        return updated_count
    
    def to_dict(self, include_user_info=False):
        """转换为字典格式"""
        data = {
            'id': self.id,
            'userId': self.user_id,
            'quotaLimit': self.quota_limit,
            'usedSpace': self.used_space,
            'availableSpace': self.get_available_space(),
            'fileCount': self.file_count,
            'folderCount': self.folder_count,
            'usagePercent': round(self.get_usage_percent(), 2),
            'isQuotaExceeded': self.is_quota_exceeded(),
            'isQuotaWarning': self.is_quota_warning(),
            'formattedUsedSpace': self.get_formatted_used_space(),
            'formattedQuotaLimit': self.get_formatted_quota_limit(),
            'formattedAvailableSpace': self.get_formatted_available_space(),
            'lastCalculatedAt': self.last_calculated_at.isoformat() if self.last_calculated_at else None,
            'createdAt': self.created_at.isoformat() if self.created_at else None,
            'updatedAt': self.updated_at.isoformat() if self.updated_at else None
        }
        
        # 包含用户信息
        if include_user_info and self.user:
            data.update({
                'username': self.user.username,
                'nickname': self.user.nickname,
                'email': self.user.email
            })
        
        return data
    
    def __repr__(self):
        return f'<UserStorageQuota user:{self.user_id} used:{self.get_formatted_used_space()}/{self.get_formatted_quota_limit()}>'